from click import Argument
from tabulate import tabulate
import json
import argparse
import os
from datetime import datetime
import re

def toHtml(shows):
    shows.sort(key=lambda log: len(log[0]), reverse=True)
    html = tabulate([[len(Logs), ErrorMsg, minDate, maxDate] for [Logs, ErrorMsg, (minDate, maxDate)] in shows], headers=['num', 'error', 'min_date', 'max_date'], tablefmt="html")
    return (html.replace('<table>', '<table border="1">'), "html")
def toJson(shows):
    shows.sort(key=lambda log: len(log[0]), reverse=True)
    return (json.dumps([{"num":len(Logs), "errmsg":ErrorMsg, "mindate":minDate, "maxdate":maxDate} for [Logs, ErrorMsg, (minDate, maxDate)] in shows], default=str), "log")
def toTable(shows):
    shows.sort(key=lambda log: len(log[0]), reverse=True)
    return (tabulate([[len(Logs), ErrorMsg, minDate, maxDate] for [Logs, ErrorMsg, (minDate, maxDate)] in shows], headers=['num', 'error', 'min_date', 'max_date'], tablefmt="fancy_grid"), "tab")

data_formats = {"html":toHtml, "json":toJson, "table":toTable}


def parse_err_log(files, dir, name, format):
    logMap = {}
    for file in files:
        parse_one_err_log(file, logMap)
    if len(logMap) == 0:
        print("no error in %s" %(files))
    shows = []
    for (_, logs) in logMap.items():
        dates = [log["date"] for log in logs["errors"]]
        shows.append([logs["errors"], logs["errmsg"], (min(dates).strftime("%Y-%m-%d %H:%M:%d.%f"), max(dates).strftime("%Y-%m-%d %H:%M:%d.%f"))])
    (data, _) = data_formats[format](shows)
    if name == "": 
        name = files[0]
    print(name)
    save = os.path.expanduser(os.path.join(dir, name))
    dir = os.path.dirname(save)
    if not os.path.exists(dir):
        os.makedirs(dir)
    with open(save, "w") as f:
        f.write(data)


def parse_one_err_log(file, logMap: dict={}):
    stackPattern = re.compile('\[\{file,.*?"\},{line,\\d+\}\]')
    reasonPattern = re.compile("ErrReason:.*, Expression=.*")
    print("file=", file)
    with open(file, 'r') as errlog:
        for i, line in enumerate(errlog):
            splits = line.split(sep="|", maxsplit=4)
            if len(splits) != 5:
                print("bad line{}: {}".format(i+1, line))
                continue
            [_, Time, _, File, ErrorMsg] = splits
            if ErrorMsg.find("Stack=") == -1:
                continue
            stack = stackPattern.findall(ErrorMsg)
            if len(stack) == 0:
                continue
            reason = reasonPattern.findall(ErrorMsg)
            if len(reason) == 0:
                continue
            Date = datetime.strptime(Time, "%Y-%m-%d_%H:%M:%S.%f")
            Errors = logMap.setdefault('\n'.join(stack), {"errmsg":ErrorMsg, "errors":[]})
            Errors["errmsg"] = ErrorMsg
            Errors["errors"].append({"rawerror":line, "date":Date})
        return logMap

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--today", action="store_true")
    parser.add_argument("--file", type=str, nargs="+", default=[])
    parser.add_argument("--name", type=str, default="")
    parser.add_argument("--dir", type=str, default="~/errlog/")
    parser.add_argument("--format", type=str, default="html", choices=['json', 'html', 'table'])
    args = parser.parse_args()
    parse_err_log([os.path.expanduser(file) for file in args.file], args.dir, args.name, args.format)
